package dingadmin

import (
	"fmt"
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/etag"
	"github.com/gofiber/fiber/v2/middleware/filesystem"
	"github.com/gofiber/fiber/v2/middleware/logger"
	recover2 "github.com/gofiber/fiber/v2/middleware/recover"
	"github.com/gofiber/fiber/v2/middleware/session"
	"github.com/gofiber/template/html"
	"github.com/op/go-logging"
	"io/fs"
	"net/http"
	"os"
)

// Engine dingadmin的主体
type Engine struct {
	configData   DingAdminConfig
	server       *fiber.App
	logger       *logging.Logger
	loggerFormat string
	asideMenus   []AsideMenu
	prefix       string
	router       fiber.Router
	messages     []TopMessage
	loginFunc    func(string, string) bool
	sessionStore *session.Store
}

// NewDingAdmin 生成新的admin
func NewDingAdmin() *Engine {
	return &Engine{configData: DingAdminConfig{
		Name:       "DingAdmin",
		Version:    "v1.0",
		Port:       80,
		ViewPath:   "./views",
		Logo:       "/logo.png",
		SearchPath: "/search",
		TimeFormat: "2006-01-02 15:04:05",
	}, loggerFormat: "%{color}%{time:15:04:05.000} %{shortfunc} ▶ %{level:.4s} %{color:reset} %{message}", asideMenus: []AsideMenu{}, prefix: "/"}
}

func (i *Engine) SetConfig(data DingAdminConfig) {
	i.configData = data
}

// SetPrefix 设置前缀 例如 ： /admin
func (i *Engine) SetPrefix(prefix string) {
	i.prefix = prefix
}

func (i *Engine) InitServer() {
	i.logger = logging.MustGetLogger("dingadmin")
	loggerBackend := logging.NewLogBackend(os.Stdout, "", 0)
	var loggerFormat = logging.MustStringFormatter(
		i.loggerFormat,
	)
	loggerBackend2 := logging.NewBackendFormatter(loggerBackend, loggerFormat)
	loggerBackendLevel := logging.AddModuleLevel(loggerBackend2)
	loggerBackendLevel.SetLevel(logging.DEBUG, "")
	logging.SetBackend(loggerBackendLevel)
	viewEngine := html.New(i.configData.ViewPath, ".html")
	viewEngine.Reload(true)
	i.addFuncs(viewEngine)
	i.sessionStore = session.New()
	i.server = fiber.New(fiber.Config{Views: viewEngine})
	i.server.Use(logger.New(), recover2.New(), etag.New())
	public_fs, _ := fs.Sub(publicFiles, "public")
	i.server.Use(filesystem.New(filesystem.Config{Root: http.FS(public_fs), Next: func(c *fiber.Ctx) bool {
		if c.Path() == "/" {
			return true
		}
		return false
	}}))
	i.router = i.server.Group(i.prefix)
	i.router.Use(func(ctx *fiber.Ctx) error {
		if i.prefix == "/" {
			if ctx.Path() == "/login" {
				return ctx.Next()
			}
		}
		if ctx.Path() == i.prefix+"/login" {
			return ctx.Next()
		}
		s, _ := i.sessionStore.Get(ctx)
		username := s.Get("username")
		if username != nil {
			password := s.Get("password")
			usernameS := fmt.Sprintf("%s", username)
			passwordS := fmt.Sprintf("%s", password)
			if i.loginFunc(usernameS, passwordS) {
				return ctx.Next()
			}
			s.Delete("username")
			s.Delete("password")
			_ = s.Save()
		}
		if i.prefix == "/" {
			return ctx.Redirect("/login")
		}
		return ctx.Redirect(i.prefix + "/login")
	})
	i.router.Get("/login", func(ctx *fiber.Ctx) error {
		return ctx.Render("login", nil)
	})
	i.router.Post("/login", func(ctx *fiber.Ctx) error {
		username := ctx.FormValue("username")
		password := ctx.FormValue("password")
		if i.loginFunc(username, password) {
			s, _ := i.sessionStore.Get(ctx)
			s.Set("username", username)
			s.Set("password", password)
			_ = s.Save()
			return ctx.JSON(fiber.Map{"status": "ok"})
		}
		return ctx.JSON(fiber.Map{"status": "no"})
	})
	i.logger.Info("DingAdmin " + Version)
	i.logger.Info("初始化完成...")
}
